/*
 * Copyright (c) 2025 CAX Conversion Project
 */
package com.comac.ins.isfd.service.impl;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

import org.bson.Document;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import cn.hutool.core.collection.CollectionUtil;
import com.anwen.mongo.aggregate.AggregateWrapper;
import com.anwen.mongo.aggregate.pipeline.Accumulators;
import com.anwen.mongo.conditions.query.LambdaQueryChainWrapper;
import com.anwen.mongo.mapper.BaseMapper;
import com.anwen.mongo.mapping.TypeReference;
import com.anwen.mongo.model.PageResult;
import com.anwen.mongo.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.comac.ins.common.core.exception.base.BaseException;
import com.comac.ins.common.core.utils.MapstructUtils;
import com.comac.ins.common.excel.utils.ExcelUtil;
import com.comac.ins.common.mybatis.core.page.TableDataInfo;
import com.comac.ins.isfd.constant.MongoDataConstant;
import com.comac.ins.isfd.constant.enums.IsfdMetadataTableNameEnum;
import com.comac.ins.isfd.constant.enums.MetaDataBusinessScenarioNoEnum;
import com.comac.ins.isfd.constant.enums.MetaDataStorageTypeEnum;
import com.comac.ins.isfd.domain.FastenerObject;
import com.comac.ins.isfd.domain.IsfdMetadata;
import com.comac.ins.isfd.domain.bo.query.FastenerQueryBo;
import com.comac.ins.isfd.domain.vo.FastenerCountObjectVo;
import com.comac.ins.isfd.domain.vo.FastenerImportObjectVo;
import com.comac.ins.isfd.domain.vo.IsfdFastenerCountObjectVo;
import com.comac.ins.isfd.domain.vo.IsfdTreeNodeVo;
import com.comac.ins.isfd.mapper.IsfdMetadataMapper;
import com.comac.ins.isfd.service.IFastenerService;
import com.comac.ins.isfd.service.IIsfdMetadataImportService;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mongodb.client.AggregateIterable;
import com.mongodb.client.MongoCollection;
import lombok.extern.slf4j.Slf4j;

/**
 * 紧固件service实现类
 *
 * @author hxloongs
 * @date 2024-7-3
 */
@Slf4j
@Service
public class IFastenerServiceImpl extends ServiceImpl<FastenerObject> implements IFastenerService, MongoDataConstant, IIsfdMetadataImportService {

    @Autowired
    private IsfdMetadataMapper isfdMetadataMapper;

    @Autowired
    private BaseMapper baseMapper;

    @Override
    public List<FastenerCountObjectVo> listCount() {
        // 1.查询元数据是否存在数据
        LambdaQueryWrapper<IsfdMetadata> lqw = Wrappers.lambdaQuery();
        lqw.eq(IsfdMetadata::getBusinessScenarioNo, MetaDataBusinessScenarioNoEnum.CAE.getValue());
        lqw.eq(IsfdMetadata::getTableName, FASTENER_EXPORT_DATA);
        IsfdMetadata isfdMetadata = isfdMetadataMapper.selectOne(lqw);

        // 2.根据元数据中的storage type进行对应的db查询统计
        List<FastenerCountObjectVo> result = new ArrayList<>();
        if (isfdMetadata != null && MetaDataStorageTypeEnum.MONGODB.getValue().equals(isfdMetadata.getStorageType())) {
            MongoCollection mongoCollection = baseMapper.getMongoPlusClient().getCollection(DB_NAME, isfdMetadata.getTableName());
            List<Document> pipeline = Arrays.asList(
                new Document($_GROUP, new Document(ID, $ + TYPE).append(COUNT, new Document($_SUM, INCLUDE)))
            );
            AggregateIterable<Document> aggregateIterable = mongoCollection.aggregate(pipeline);
            aggregateIterable.forEach(document -> {
                FastenerCountObjectVo fastenerCountObjectVo = new FastenerCountObjectVo();
                fastenerCountObjectVo.setType(document.getString(ID));
                fastenerCountObjectVo.setCount(document.getLong(COUNT));
                result.add(fastenerCountObjectVo);
            });
        }
        return result;
    }

    @Override
    public List<IsfdFastenerCountObjectVo> listCountByListByField(String field) {
        AggregateWrapper groupAggregateWrapper = new AggregateWrapper();
        groupAggregateWrapper.group("$" + field,
            Accumulators.sum(field, 1));

        List<Map<String, Object>> maps = baseMapper.aggregateList(DB_NAME, FASTENER_EXPORT_DATA, groupAggregateWrapper, new TypeReference<Map<String, Object>>() {
        });
        return maps.stream()
            .map(item -> new IsfdFastenerCountObjectVo(null, (String) item.get("_id"), Long.valueOf(item.get(field).toString())))
            .toList();
    }

    @Override
    public IsfdTreeNodeVo listTree() {
        // 初始化最外层root节点
        IsfdTreeNodeVo<IsfdTreeNodeVo> rootNode = new IsfdTreeNodeVo("-1", "root", "root", null);

        // 查询元数据是否存在数据
        LambdaQueryWrapper<IsfdMetadata> lqw = Wrappers.lambdaQuery();
        lqw.eq(IsfdMetadata::getBusinessScenarioNo, MetaDataBusinessScenarioNoEnum.CAE.getValue());
        lqw.eq(IsfdMetadata::getTableName, FASTENER_EXPORT_DATA);
        IsfdMetadata isfdMetadata = isfdMetadataMapper.selectOne(lqw);
        if (isfdMetadata == null) {
            return rootNode;
        }

        // 封装子节点
        if (MetaDataStorageTypeEnum.MONGODB.getValue().equals(isfdMetadata.getStorageType())) {
            rootNode.setChildren(new ArrayList<>());
            List<Map<String, Object>> result = baseMapper.list(isfdMetadata.getTableName(), new TypeReference<Map<String, Object>>() {
            });
            //根据type分组
            Map<String, List<Map<String, Object>>> groupedResults = result.stream().collect(Collectors.groupingBy(record -> record.get("type").toString()));
            AtomicInteger counter = new AtomicInteger(0);
            groupedResults.forEach((type, group) -> {
                IsfdTreeNodeVo node = new IsfdTreeNodeVo();
                node.setNodeId(String.valueOf(counter.incrementAndGet()));
                node.setNodeType(type);
                node.setNodeName(type);
                node.setChildren(group);
                rootNode.getChildren().add(node);
            });
        }
        return rootNode;
    }

    @Override
    public TableDataInfo<FastenerImportObjectVo> queryPageList(FastenerQueryBo queryBo) {
        // 构造返回列表
        List<FastenerObject> fastenerObjectList = new ArrayList<>();
        Integer pageNum = queryBo.getPageNum();
        Integer pageSize = queryBo.getPageSize();

        // 构造查询参数
        LambdaQueryChainWrapper<FastenerObject> queryChainWrapper = this.lambdaQuery();
        queryChainWrapper.in(CollectionUtil.isNotEmpty(queryBo.getMetadataManagementIds()), FastenerObject::getMetadataManagementId, queryBo.getMetadataManagementIds());

        // 进行mongodb分页查询
        PageResult<FastenerObject> page = this.page(queryChainWrapper, pageNum, pageSize);
        fastenerObjectList.addAll(page.getContentData());
        Long total = page.getTotalSize();

        // 空集直接返回
        if (CollectionUtil.isEmpty(fastenerObjectList)) {
            return TableDataInfo.build();
        }
        // 返回vos
        List<FastenerImportObjectVo> voList = MapstructUtils.convert(fastenerObjectList, FastenerImportObjectVo.class);

        return TableDataInfo.buildToPageMemoryLimit(Boolean.FALSE, voList, pageNum, pageSize, total);
    }

    @Override
    public String selectByTableName() {
        return IsfdMetadataTableNameEnum.FASTENER_EXPORTDATA.getValue();
    }

    @Override
    public Long excelImport(File excelImportFile, String metadataManagementId) {
        long successCount = 0L;
        ObjectMapper objectMapper = new ObjectMapper();
        try (InputStream is = new FileInputStream(excelImportFile)) {
            String fileName = excelImportFile.getName();
            String extension = fileName.substring(fileName.lastIndexOf(".") + 1);
            List<FastenerImportObjectVo> targetVos = new ArrayList<>();
            if (extension.equals("json")) {
                targetVos = objectMapper.readValue(is, new com.fasterxml.jackson.core.type.TypeReference<>() {
                });
            } else if (extension.equals("xlsx")) {
                targetVos = ExcelUtil.importExcel(is, FastenerImportObjectVo.class);
            } else {
                throw new BaseException("文件类型不支持：" + extension);
            }
            // 获取紧固件库
            MongoCollection<Document> mongoCollection = baseMapper.getMongoPlusClient().getCollection(DB_NAME, FASTENER_EXPORT_DATA);
            for (FastenerImportObjectVo vo : targetVos) {
                try {
                    vo.setMetadataManagementId(metadataManagementId);
                    replaceNullsWithEmptyStrings(vo);
                    // 将vo转换成doc, 插入紧固件库
                    Document document = convertVoToDocument(vo);
                    mongoCollection.insertOne(document);
                    successCount++;
                } catch (Exception e) {
                    log.error("紧固件数据导入失败", e);
                }
            }

        } catch (Exception e) {
            log.error("sheet文件转换为实体类失败", e);
            throw new BaseException("sheet文件转换为实体类失败");
        }

        return successCount;
    }

    /**
     * 将VO对象中的null值替换为空字符串。
     *
     * @param vo 要处理的对象。
     * @throws IllegalAccessException 如果不能访问字段。
     */
    public static void replaceNullsWithEmptyStrings(Object vo) throws IllegalAccessException {
        Class<?> clazz = vo.getClass();
        for (Field field : clazz.getDeclaredFields()) {
            field.setAccessible(true); // 设置为可访问私有变量
            if (field.get(vo) == null) {
                field.set(vo, "");
            }
        }
    }

    private Document convertVoToDocument(FastenerImportObjectVo vo) {
        ObjectMapper mapper = new ObjectMapper();
        try {
            Map<String, Object> map = mapper.convertValue(vo, Map.class);
            return new Document(map);
        } catch (Exception e) {
            log.error("实体类转换为Docuement失败", e);
            throw new BaseException("实体类转换为Docuement失败");
        }
    }
}
